/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 *    Neil Roberts <neil@linux.intel.com>
 *
 */

/** @file bptc-modes.c
 *
 * Tests a BPTC-compressed half-float texture with a block for each of
 * the possible 14 modes. The texture is retrieved with glGetTexImage
 * and verified that it has the expected values.
 */

#include "piglit-util-gl.h"

PIGLIT_GL_TEST_CONFIG_BEGIN

	config.supports_gl_compat_version = 10;

	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
	config.khr_no_error_support = PIGLIT_NO_ERRORS;

PIGLIT_GL_TEST_CONFIG_END

#define BLOCK_SIZE 4
#define BLOCK_BYTES 16
#define N_PARTITIONS 32

struct bptc_float_bitfield {
   int8_t endpoint;
   uint8_t component;
   uint8_t offset;
   uint8_t n_bits;
   bool reverse;
};

struct bptc_float_mode {
   int n_partition_bits;
   int n_index_bits;
   struct bptc_float_bitfield bitfields[24];
};

static const struct bptc_float_mode
bptc_float_modes[] = {
   /* 00 */
   { 5, 3,
     { { 2, 1, 4, 1, false }, { 2, 2, 4, 1, false }, { 3, 2, 4, 1, false },
       { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false },
       { 1, 0, 0, 5, false }, { 3, 1, 4, 1, false }, { 2, 1, 0, 4, false },
       { 1, 1, 0, 5, false }, { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false },
       { 1, 2, 0, 5, false }, { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false },
       { 2, 0, 0, 5, false }, { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false },
       { 3, 2, 3, 1, false },
       { -1 } }
   },
   /* 01 */
   { 5, 3,
     { { 2, 1, 5, 1, false }, { 3, 1, 4, 1, false }, { 3, 1, 5, 1, false },
       { 0, 0, 0, 7, false }, { 3, 2, 0, 1, false }, { 3, 2, 1, 1, false },
       { 2, 2, 4, 1, false }, { 0, 1, 0, 7, false }, { 2, 2, 5, 1, false },
       { 3, 2, 2, 1, false }, { 2, 1, 4, 1, false }, { 0, 2, 0, 7, false },
       { 3, 2, 3, 1, false }, { 3, 2, 5, 1, false }, { 3, 2, 4, 1, false },
       { 1, 0, 0, 6, false }, { 2, 1, 0, 4, false }, { 1, 1, 0, 6, false },
       { 3, 1, 0, 4, false }, { 1, 2, 0, 6, false }, { 2, 2, 0, 4, false },
       { 2, 0, 0, 6, false },
       { 3, 0, 0, 6, false },
       { -1 } }
   },
   /* 00010 */
   { 5, 3,
     { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false },
       { 1, 0, 0, 5, false }, { 0, 0, 10, 1, false }, { 2, 1, 0, 4, false },
       { 1, 1, 0, 4, false }, { 0, 1, 10, 1, false }, { 3, 2, 0, 1, false },
       { 3, 1, 0, 4, false }, { 1, 2, 0, 4, false }, { 0, 2, 10, 1, false },
       { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 5, false },
       { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false }, { 3, 2, 3, 1, false },
       { -1 } }
   },
   /* 00011 */
   { 0, 4,
     { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false },
       { 1, 0, 0, 10, false }, { 1, 1, 0, 10, false }, { 1, 2, 0, 10, false },
       { -1 } }
   },
   /* 00110 */
   { 5, 3,
     { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false },
       { 1, 0, 0, 4, false }, { 0, 0, 10, 1, false }, { 3, 1, 4, 1, false },
       { 2, 1, 0, 4, false }, { 1, 1, 0, 5, false }, { 0, 1, 10, 1, false },
       { 3, 1, 0, 4, false }, { 1, 2, 0, 4, false }, { 0, 2, 10, 1, false },
       { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 4, false },
       { 3, 2, 0, 1, false }, { 3, 2, 2, 1, false }, { 3, 0, 0, 4, false },
       { 2, 1, 4, 1, false }, { 3, 2, 3, 1, false },
       { -1 } }
   },
   /* 00111 */
   { 0, 4,
     { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false },
       { 1, 0, 0, 9, false }, { 0, 0, 10, 1, false }, { 1, 1, 0, 9, false },
       { 0, 1, 10, 1, false }, { 1, 2, 0, 9, false }, { 0, 2, 10, 1, false },
       { -1 } }
   },
   /* 01010 */
   { 5, 3,
     { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false },
       { 1, 0, 0, 4, false }, { 0, 0, 10, 1, false }, { 2, 2, 4, 1, false },
       { 2, 1, 0, 4, false }, { 1, 1, 0, 4, false }, { 0, 1, 10, 1, false },
       { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false }, { 1, 2, 0, 5, false },
       { 0, 2, 10, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 4, false },
       { 3, 2, 1, 1, false }, { 3, 2, 2, 1, false }, { 3, 0, 0, 4, false },
       { 3, 2, 4, 1, false }, { 3, 2, 3, 1, false },
       { -1 } }
   },
   /* 01011 */
   { 0, 4,
     { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false },
       { 1, 0, 0, 8, false }, { 0, 0, 10, 2, true }, { 1, 1, 0, 8, false },
       { 0, 1, 10, 2, true }, { 1, 2, 0, 8, false }, { 0, 2, 10, 2, true },
       { -1 } }
   },
   /* 01110 */
   { 5, 3,
     { { 0, 0, 0, 9, false }, { 2, 2, 4, 1, false }, { 0, 1, 0, 9, false },
       { 2, 1, 4, 1, false }, { 0, 2, 0, 9, false }, { 3, 2, 4, 1, false },
       { 1, 0, 0, 5, false }, { 3, 1, 4, 1, false }, { 2, 1, 0, 4, false },
       { 1, 1, 0, 5, false }, { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false },
       { 1, 2, 0, 5, false }, { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false },
       { 2, 0, 0, 5, false }, { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false },
       { 3, 2, 3, 1, false },
       { -1 } }
   },
   /* 01111 */
   { 0, 4,
     { { 0, 0, 0, 10, false }, { 0, 1, 0, 10, false }, { 0, 2, 0, 10, false },
       { 1, 0, 0, 4, false }, { 0, 0, 10, 6, true }, { 1, 1, 0, 4, false },
       { 0, 1, 10, 6, true }, { 1, 2, 0, 4, false }, { 0, 2, 10, 6, true },
       { -1 } }
   },
   /* 10010 */
   { 5, 3,
     { { 0, 0, 0, 8, false }, { 3, 1, 4, 1, false }, { 2, 2, 4, 1, false },
       { 0, 1, 0, 8, false }, { 3, 2, 2, 1, false }, { 2, 1, 4, 1, false },
       { 0, 2, 0, 8, false }, { 3, 2, 3, 1, false }, { 3, 2, 4, 1, false },
       { 1, 0, 0, 6, false }, { 2, 1, 0, 4, false }, { 1, 1, 0, 5, false },
       { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false }, { 1, 2, 0, 5, false },
       { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 6, false },
       { 3, 0, 0, 6, false },
       { -1 } }
   },
   /* 10011 */
   { 0 /* reserved */ },
   /* 10110 */
   { 5, 3,
     { { 0, 0, 0, 8, false }, { 3, 2, 0, 1, false }, { 2, 2, 4, 1, false },
       { 0, 1, 0, 8, false }, { 2, 1, 5, 1, false }, { 2, 1, 4, 1, false },
       { 0, 2, 0, 8, false }, { 3, 1, 5, 1, false }, { 3, 2, 4, 1, false },
       { 1, 0, 0, 5, false }, { 3, 1, 4, 1, false }, { 2, 1, 0, 4, false },
       { 1, 1, 0, 6, false }, { 3, 1, 0, 4, false }, { 1, 2, 0, 5, false },
       { 3, 2, 1, 1, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 5, false },
       { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false }, { 3, 2, 3, 1, false },
       { -1 } }
   },
   /* 10111 */
   { 0 /* reserved */ },
   /* 11010 */
   { 5, 3,
     { { 0, 0, 0, 8, false }, { 3, 2, 1, 1, false }, { 2, 2, 4, 1, false },
       { 0, 1, 0, 8, false }, { 2, 2, 5, 1, false }, { 2, 1, 4, 1, false },
       { 0, 2, 0, 8, false }, { 3, 2, 5, 1, false }, { 3, 2, 4, 1, false },
       { 1, 0, 0, 5, false }, { 3, 1, 4, 1, false }, { 2, 1, 0, 4, false },
       { 1, 1, 0, 5, false }, { 3, 2, 0, 1, false }, { 3, 1, 0, 4, false },
       { 1, 2, 0, 6, false }, { 2, 2, 0, 4, false }, { 2, 0, 0, 5, false },
       { 3, 2, 2, 1, false }, { 3, 0, 0, 5, false }, { 3, 2, 3, 1, false },
       { -1 } }
   },
   /* 11011 */
   { 0 /* reserved */ },
   /* 11110 */
   { 5, 3,
     { { 0, 0, 0, 6, false }, { 3, 1, 4, 1, false }, { 3, 2, 0, 1, false },
       { 3, 2, 1, 1, false }, { 2, 2, 4, 1, false }, { 0, 1, 0, 6, false },
       { 2, 1, 5, 1, false }, { 2, 2, 5, 1, false }, { 3, 2, 2, 1, false },
       { 2, 1, 4, 1, false }, { 0, 2, 0, 6, false }, { 3, 1, 5, 1, false },
       { 3, 2, 3, 1, false }, { 3, 2, 5, 1, false }, { 3, 2, 4, 1, false },
       { 1, 0, 0, 6, false }, { 2, 1, 0, 4, false }, { 1, 1, 0, 6, false },
       { 3, 1, 0, 4, false }, { 1, 2, 0, 6, false }, { 2, 2, 0, 4, false },
       { 2, 0, 0, 6, false }, { 3, 0, 0, 6, false },
       { -1 } }
   },
   /* 11111 */
   { 0 /* reserved */ },
};

static const uint8_t
anchor_indices[N_PARTITIONS] = {
	/* Anchor index values for the second subset of two-subset
	 * partitioning */
	0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
	0xf,0x2,0x8,0x2,0x2,0x8,0x8,0xf,0x2,0x8,0x2,0x2,0x8,0x8,0x2,0x2
};

struct bptc_block {
	int mode;
	int partition;
	uint16_t endpoints[2 * 2][3];
	uint8_t indices[BLOCK_SIZE * BLOCK_SIZE];
	GLhalfNV signed_expected_values[BLOCK_SIZE * BLOCK_SIZE * 3];
	GLhalfNV unsigned_expected_values[BLOCK_SIZE * BLOCK_SIZE * 3];
};

static const struct bptc_block
bptc_blocks[] = {
	{
		0, /* mode */
		0, /* partition */
		{
			 { 0x0167, 0x03c6, 0x0069 },
			 { 0x0013, 0x0011, 0x001f },
			 { 0x000a, 0x000c, 0x0009 },
			 { 0x000d, 0x001a, 0x000b }
		},
		{
			0x2, 0x3, 0x3, 0x6, /* subsets 0(a) 0    1    1    */
			0x4, 0x2, 0x4, 0x0, /* subsets 0    0    1    1    */
			0x3, 0x0, 0x7, 0x5, /* subsets 0    0    1    1    */
			0x6, 0x2, 0x6, 0x3  /* subsets 0    0    1    1(a) */
		},
		{
			0x562e, 0x8f30, 0x197b, 0x55bc, 0x8fb3, 0x1972,
			0x59cb, 0x8d19, 0x1bef, 0x5a1c, 0x8f02, 0x1c25,
			0x553f, 0x9044, 0x1969, 0x562e, 0x8f30, 0x197b,
			0x59e8, 0x8dc8, 0x1c02, 0x597d, 0x8b43, 0x1bbb,
			0x55bc, 0x8fb3, 0x1972, 0x5711, 0x8e2b, 0x198d,
			0x5a37, 0x8f9f, 0x1c37, 0x5a02, 0x8e65, 0x1c14,
			0x545c, 0x914a, 0x1957, 0x562e, 0x8f30, 0x197b,
			0x5a1c, 0x8f02, 0x1c25, 0x59cb, 0x8d19, 0x1bef
		},
		{
			0x2b17, 0x7486, 0x0cbd, 0x2ade, 0x7445, 0x0cb9,
			0x2ce5, 0x7592, 0x0df7, 0x2d0e, 0x749d, 0x0e12,
			0x2a9f, 0x73fc, 0x0cb4, 0x2b17, 0x7486, 0x0cbd,
			0x2cf4, 0x753a, 0x0e01, 0x2cbe, 0x767d, 0x0ddd,
			0x2ade, 0x7445, 0x0cb9, 0x2b88, 0x7509, 0x0cc6,
			0x2d1b, 0x744f, 0x0e1b, 0x2d01, 0x74ec, 0x0e0a,
			0x2a2e, 0x7379, 0x0cab, 0x2b17, 0x7486, 0x0cbd,
			0x2d0e, 0x749d, 0x0e12, 0x2ce5, 0x7592, 0x0df7
		}
	},
	{
		1, /* mode */
		1, /* partition */
		{
			 { 0x0033, 0x001f, 0x0049 },
			 { 0x001a, 0x0026, 0x0032 },
			 { 0x000d, 0x0037, 0x0031 },
			 { 0x0018, 0x0023, 0x001a }
		},
		{
			0x1, 0x5, 0x5, 0x7, /* subsets 0(a) 0    0    1    */
			0x0, 0x1, 0x6, 0x4, /* subsets 0    0    0    1    */
			0x3, 0x2, 0x5, 0x6, /* subsets 0    0    0    1    */
			0x3, 0x4, 0x4, 0x1  /* subsets 0    0    0    1(a) */
		},
		{
			0x47b7, 0x35f2, 0xcc32, 0xaba7, 0x18d3, 0x349d,
			0xaba7, 0x18d3, 0x349d, 0xe7a8, 0x04d8, 0xb928,
			0x63c8, 0x3d08, 0xeb88, 0x47b7, 0x35f2, 0xcc32,
			0xc7b7, 0x11bd, 0x53f2, 0xf03d, 0x1531, 0x0ec6,
			0x0f97, 0x27c7, 0x8d88, 0x2ba7, 0x2edd, 0xacdd,
			0xaba7, 0x18d3, 0x349d, 0xea84, 0x0a4b, 0xa12e,
			0x0f97, 0x27c7, 0x8d88, 0x8f97, 0x1fe8, 0x1548,
			0x8f97, 0x1fe8, 0x1548, 0xf922, 0x2625, 0x595e
		},
		{
			0x356e, 0x1af9, 0x454b, 0x43fe, 0x0c69, 0x3d74,
			0x43fe, 0x0c69, 0x3d74, 0x4924, 0x026c, 0x6064,
			0x31e4, 0x1e84, 0x4734, 0x356e, 0x1af9, 0x454b,
			0x4789, 0x08de, 0x3b8c, 0x44a5, 0x0a98, 0x4fa2,
			0x3c84, 0x13e3, 0x417b, 0x38f9, 0x176e, 0x4363,
			0x43fe, 0x0c69, 0x3d74, 0x47a4, 0x0525, 0x5ace,
			0x3c84, 0x13e3, 0x417b, 0x4073, 0x0ff4, 0x3f5c,
			0x4073, 0x0ff4, 0x3f5c, 0x3ffb, 0x1312, 0x3e41
		}
	},
	{
		2, /* mode */
		2, /* partition */
		{
			 { 0x040e, 0x0582, 0x0074 },
			 { 0x0001, 0x0001, 0x000d },
			 { 0x001c, 0x0007, 0x0000 },
			 { 0x0009, 0x000e, 0x0001 }
		},
		{
			0x1, 0x1, 0x4, 0x7, /* subsets 0(a) 1    1    1    */
			0x6, 0x1, 0x6, 0x7, /* subsets 0    1    1    1    */
			0x2, 0x4, 0x3, 0x6, /* subsets 0    1    1    1    */
			0x7, 0x0, 0x4, 0x2  /* subsets 0    1    1    1(a) */
		},
		{
			0xfa58, 0xcd4c, 0x0e0e, 0xfaa0, 0xcc9f, 0x0e20,
			0xf9f0, 0xcd19, 0x0e2d, 0xf946, 0xcd8f, 0x0e3a,
			0xfa42, 0xcd36, 0x0dcc, 0xfaa0, 0xcc9f, 0x0e20,
			0xf97e, 0xcd67, 0x0e36, 0xf946, 0xcd8f, 0x0e3a,
			0xfa54, 0xcd48, 0x0e01, 0xf9f0, 0xcd19, 0x0e2d,
			0xfa2f, 0xcced, 0x0e29, 0xf97e, 0xcd67, 0x0e36,
			0xfa3e, 0xcd32, 0x0dbe, 0xfad9, 0xcc78, 0x0e1b,
			0xf9f0, 0xcd19, 0x0e2d, 0xfa68, 0xccc6, 0x0e24
		},
		{
			0x3ee3, 0x5569, 0x0707, 0x3ebf, 0x55bf, 0x0710,
			0x3f17, 0x5582, 0x0716, 0x3f6c, 0x5547, 0x071d,
			0x3eee, 0x5574, 0x06e6, 0x3ebf, 0x55bf, 0x0710,
			0x3f50, 0x555b, 0x071b, 0x3f6c, 0x5547, 0x071d,
			0x3ee5, 0x556b, 0x0700, 0x3f17, 0x5582, 0x0716,
			0x3ef8, 0x5598, 0x0714, 0x3f50, 0x555b, 0x071b,
			0x3ef0, 0x5576, 0x06df, 0x3ea2, 0x55d3, 0x070d,
			0x3f17, 0x5582, 0x0716, 0x3edb, 0x55ac, 0x0712
		}
	},
	{
		3, /* mode */
		0, /* partition (not used) */
		{
			 { 0x02ec, 0x00b0, 0x003b },
			 { 0x02fb, 0x0232, 0x00af }
		},
		{
			0x4, 0x4, 0xc, 0x8, /* subsets 0(a) 0    0    0    */
			0xb, 0xc, 0x2, 0xa, /* subsets 0    0    0    0    */
			0xe, 0x3, 0xb, 0xa, /* subsets 0    0    0    0    */
			0xa, 0xa, 0xb, 0x9  /* subsets 0    0    0    0    */
		},
		{
			0xc1ff, 0x01a3, 0x15df, 0xc1ff, 0x01a3, 0x15df,
			0xc011, 0xd093, 0x24cc, 0xc108, 0xa778, 0x1d55,
			0xc04c, 0xc6e7, 0x230a, 0xc011, 0xd093, 0x24cc,
			0xc274, 0x14fb, 0x125c, 0xc086, 0xbd3b, 0x2149,
			0xbf8f, 0xe656, 0x28bf, 0xc23a, 0x0b4f, 0x141d,
			0xc04c, 0xc6e7, 0x230a, 0xc086, 0xbd3b, 0x2149,
			0xc086, 0xbd3b, 0x2149, 0xc086, 0xbd3b, 0x2149,
			0xc04c, 0xc6e7, 0x230a, 0xc0ce, 0xb124, 0x1f17
		},
		{
			0x5b1f, 0x21c9, 0x0aef, 0x5b1f, 0x21c9, 0x0aef,
			0x5c16, 0x3a9e, 0x1266, 0x5b9a, 0x2e34, 0x0eaa,
			0x5bf8, 0x37b3, 0x1185, 0x5c16, 0x3a9e, 0x1266,
			0x5ae4, 0x1bf2, 0x092e, 0x5bdb, 0x34c7, 0x10a4,
			0x5c57, 0x4131, 0x145f, 0x5b01, 0x1ede, 0x0a0e,
			0x5bf8, 0x37b3, 0x1185, 0x5bdb, 0x34c7, 0x10a4,
			0x5bdb, 0x34c7, 0x10a4, 0x5bdb, 0x34c7, 0x10a4,
			0x5bf8, 0x37b3, 0x1185, 0x5bb7, 0x3120, 0x0f8b
		}
	},
	{
		6, /* mode */
		3, /* partition */
		{
			 { 0x05d1, 0x07e6, 0x0005 },
			 { 0x000c, 0x001c, 0x0004 },
			 { 0x0005, 0x0018, 0x000e },
			 { 0x0001, 0x0009, 0x0009 }
		},
		{
			0x0, 0x3, 0x0, 0x1, /* subsets 0(a) 0    0    1    */
			0x7, 0x5, 0x1, 0x3, /* subsets 0    0    1    1    */
			0x1, 0x3, 0x5, 0x7, /* subsets 0    0    1    1    */
			0x7, 0x0, 0x1, 0x1  /* subsets 0    1    1    1(a) */
		},
		{
			0xc3c0, 0x8335, 0x00aa, 0xc3f4, 0x8369, 0x00de,
			0xc3c0, 0x8335, 0x00aa, 0xc336, 0x83e2, 0x0052,
			0xc43c, 0x83b1, 0x0126, 0xc419, 0x838e, 0x0103,
			0xc336, 0x83e2, 0x0052, 0xc359, 0x834e, 0x001e,
			0xc3d1, 0x8346, 0x00bb, 0xc3f4, 0x8369, 0x00de,
			0xc37e, 0x82b2, 0x8019, 0xc3a1, 0x821e, 0x804d,
			0xc43c, 0x83b1, 0x0126, 0xc325, 0x842d, 0x006c,
			0xc336, 0x83e2, 0x0052, 0xc336, 0x83e2, 0x0052
		},
		{
			0x5a2f, 0x7a74, 0x0055, 0x5a15, 0x7a5a, 0x006f,
			0x5a2f, 0x7a74, 0x0055, 0x5a74, 0x7a1e, 0x119b,
			0x59f1, 0x7a36, 0x0093, 0x5a02, 0x7a48, 0x0081,
			0x5a74, 0x7a1e, 0x119b, 0x5a62, 0x7a68, 0x3465,
			0x5a26, 0x7a6c, 0x005d, 0x5a15, 0x7a5a, 0x006f,
			0x5a50, 0x7ab6, 0x591e, 0x5a3e, 0x7b00, 0x7be8,
			0x59f1, 0x7a36, 0x0093, 0x5a7c, 0x79f8, 0x0036,
			0x5a74, 0x7a1e, 0x119b, 0x5a74, 0x7a1e, 0x119b
		}
	},
	{
		7, /* mode */
		0, /* partition (not used) */
		{
			 { 0x023a, 0x02e5, 0x07ca },
			 { 0x000b, 0x00cb, 0x01d0 }
		},
		{
			0x0, 0x7, 0x4, 0xd, /* subsets 0(a) 0    0    0    */
			0xf, 0x3, 0xe, 0x8, /* subsets 0    0    0    0    */
			0xc, 0xb, 0x4, 0x5, /* subsets 0    0    0    0    */
			0x4, 0x3, 0xa, 0x5  /* subsets 0    0    0    0    */
		},
		{
			0x4515, 0x59ca, 0x8699, 0x45b5, 0x6550, 0x8953,
			0x4570, 0x6052, 0x8824, 0x463b, 0x6eeb, 0x8b98,
			0x466a, 0x725f, 0x8c69, 0x455b, 0x5ec9, 0x87c7,
			0x4655, 0x70d6, 0x8c0c, 0x45ca, 0x66d9, 0x89b0,
			0x4625, 0x6d61, 0x8b3b, 0x4610, 0x6bd8, 0x8ade,
			0x4570, 0x6052, 0x8824, 0x4585, 0x61db, 0x8881,
			0x4570, 0x6052, 0x8824, 0x455b, 0x5ec9, 0x87c7,
			0x45fb, 0x6a4f, 0x8a81, 0x4585, 0x61db, 0x8881
		},
		{
			0x228a, 0x2ce5, 0x78c2, 0x22da, 0x32a8, 0x7766,
			0x22b8, 0x3029, 0x77fd, 0x231d, 0x3775, 0x7643,
			0x2335, 0x392f, 0x75da, 0x22ad, 0x2f64, 0x782b,
			0x232a, 0x386b, 0x7609, 0x22e5, 0x336c, 0x7737,
			0x2312, 0x36b0, 0x7671, 0x2308, 0x35ec, 0x76a0,
			0x22b8, 0x3029, 0x77fd, 0x22c2, 0x30ed, 0x77ce,
			0x22b8, 0x3029, 0x77fd, 0x22ad, 0x2f64, 0x782b,
			0x22fd, 0x3527, 0x76ce, 0x22c2, 0x30ed, 0x77ce
		}
	},
	{
		10, /* mode */
		4, /* partition */
		{
			 { 0x015e, 0x034b, 0x0379 },
			 { 0x0003, 0x000b, 0x0010 },
			 { 0x0004, 0x0004, 0x0011 },
			 { 0x000e, 0x0009, 0x001c }
		},
		{
			0x2, 0x4, 0x4, 0x2, /* subsets 0(a) 0    0    0    */
			0x3, 0x0, 0x7, 0x3, /* subsets 0    0    0    1    */
			0x3, 0x5, 0x3, 0x0, /* subsets 0    0    0    1    */
			0x0, 0x7, 0x5, 0x0  /* subsets 0    0    1    1(a) */
		},
		{
			0x2a8b, 0x65f8, 0x6b2b, 0x2aa7, 0x65cb, 0x6a97,
			0x2aa7, 0x65cb, 0x6a97, 0x2a8b, 0x65f8, 0x6b2b,
			0x2a99, 0x65e3, 0x6ae5, 0x2a71, 0x6624, 0x6bb6,
			0x2ace, 0x6589, 0x69c6, 0x2a9f, 0x6611, 0x6a75,
			0x2a99, 0x65e3, 0x6ae5, 0x2ab4, 0x65b5, 0x6a52,
			0x2a99, 0x65e3, 0x6ae5, 0x2aed, 0x66a0, 0x69e5,
			0x2a71, 0x6624, 0x6bb6, 0x2ace, 0x6589, 0x69c6,
			0x2a67, 0x65ab, 0x6ada, 0x2aed, 0x66a0, 0x69e5
		},
		{
			0x1545, 0x32fc, 0x3595, 0x1553, 0x32e5, 0x354b,
			0x1553, 0x32e5, 0x354b, 0x1545, 0x32fc, 0x3595,
			0x154c, 0x32f1, 0x3572, 0x1538, 0x3312, 0x35db,
			0x1567, 0x32c4, 0x34e3, 0x154f, 0x3308, 0x353a,
			0x154c, 0x32f1, 0x3572, 0x155a, 0x32da, 0x3529,
			0x154c, 0x32f1, 0x3572, 0x1576, 0x3350, 0x34f2,
			0x1538, 0x3312, 0x35db, 0x1567, 0x32c4, 0x34e3,
			0x1533, 0x32d5, 0x356d, 0x1576, 0x3350, 0x34f2
		}
	},
	{
		11, /* mode */
		0, /* partition (not used) */
		{
			 { 0x0fbb, 0x016f, 0x0422 },
			 { 0x0019, 0x00ba, 0x009b }
		},
		{
			0x5, 0x5, 0xb, 0x1, /* subsets 0(a) 0    0    0    */
			0xa, 0xc, 0xf, 0x3, /* subsets 0    0    0    0    */
			0x8, 0x9, 0x8, 0x4, /* subsets 0    0    0    0    */
			0xb, 0x3, 0x5, 0xa  /* subsets 0    0    0    0    */
		},
		{
			0x83b6, 0x14dc, 0x3e15, 0x83b6, 0x14dc, 0x3e15,
			0x8318, 0x1323, 0x3b98, 0x841d, 0x15fc, 0x3fb4,
			0x8330, 0x1367, 0x3bfa, 0x8300, 0x12e0, 0x3b37,
			0x82b1, 0x1203, 0x39f9, 0x83e6, 0x1564, 0x3ed9,
			0x8366, 0x13ff, 0x3cd7, 0x834e, 0x13bc, 0x3c75,
			0x8366, 0x13ff, 0x3cd7, 0x83ce, 0x1520, 0x3e77,
			0x8318, 0x1323, 0x3b98, 0x83e6, 0x1564, 0x3ed9,
			0x83b6, 0x14dc, 0x3e15, 0x8330, 0x1367, 0x3bfa
		},
		{
			0x7a2c, 0x0a6e, 0x1f0a, 0x7a2c, 0x0a6e, 0x1f0a,
			0x7a7b, 0x0991, 0x1dcc, 0x79f9, 0x0afe, 0x1fda,
			0x7a6f, 0x09b3, 0x1dfd, 0x7a87, 0x0970, 0x1d9b,
			0x7aae, 0x0901, 0x1cfc, 0x7a14, 0x0ab2, 0x1f6c,
			0x7a54, 0x09ff, 0x1e6b, 0x7a60, 0x09de, 0x1e3a,
			0x7a54, 0x09ff, 0x1e6b, 0x7a20, 0x0a90, 0x1f3b,
			0x7a7b, 0x0991, 0x1dcc, 0x7a14, 0x0ab2, 0x1f6c,
			0x7a2c, 0x0a6e, 0x1f0a, 0x7a6f, 0x09b3, 0x1dfd
		}
	},
	{
		14, /* mode */
		5, /* partition */
		{
			 { 0x014e, 0x01e8, 0x0098 },
			 { 0x0012, 0x0018, 0x0000 },
			 { 0x0019, 0x000d, 0x001d },
			 { 0x0014, 0x001c, 0x001f }
		},
		{
			0x2, 0x7, 0x2, 0x3, /* subsets 0(a) 0    1    1    */
			0x4, 0x5, 0x4, 0x6, /* subsets 0    1    1    1    */
			0x1, 0x3, 0x2, 0x2, /* subsets 0    1    1    1    */
			0x5, 0x2, 0x6, 0x0  /* subsets 1    1    1    1(a) */
		},
		{
			0xd85e, 0x8cf5, 0x49de, 0xdd3e, 0x8fbe, 0x49de,
			0xda88, 0x87e2, 0x48af, 0xdadf, 0x890b, 0x48d2,
			0xda61, 0x8e1b, 0x49de, 0xdb97, 0x8b7d, 0x491c,
			0xdb40, 0x8a54, 0x48f9, 0xdbee, 0x8ca5, 0x493f,
			0xd76a, 0x8c69, 0x49de, 0xdadf, 0x890b, 0x48d2,
			0xda88, 0x87e2, 0x48af, 0xda88, 0x87e2, 0x48af,
			0xdb97, 0x8b7d, 0x491c, 0xda88, 0x87e2, 0x48af,
			0xdbee, 0x8ca5, 0x493f, 0xd9da, 0x8592, 0x486a
		},
		{
			0x500e, 0x75c3, 0x24ef, 0x4d9f, 0x745f, 0x24ef,
			0x4ef9, 0x784c, 0x2457, 0x4ece, 0x77b8, 0x2469,
			0x4f0d, 0x7530, 0x24ef, 0x4e72, 0x767f, 0x248e,
			0x4e9d, 0x7713, 0x247c, 0x4e46, 0x75eb, 0x249f,
			0x5088, 0x7609, 0x24ef, 0x4ece, 0x77b8, 0x2469,
			0x4ef9, 0x784c, 0x2457, 0x4ef9, 0x784c, 0x2457,
			0x4e72, 0x767f, 0x248e, 0x4ef9, 0x784c, 0x2457,
			0x4e46, 0x75eb, 0x249f, 0x4f51, 0x7975, 0x2435
		}
	},
	{
		15, /* mode */
		0, /* partition (not used) */
		{
			 { 0x21b5, 0xe373, 0x173b },
			 { 0x0004, 0x000c, 0x0003 }
		},
		{
			0x6, 0x4, 0x3, 0xf, /* subsets 0(a) 0    0    0    */
			0x2, 0x0, 0x4, 0xe, /* subsets 0    0    0    0    */
			0xf, 0x2, 0x5, 0x9, /* subsets 0    0    0    0    */
			0xd, 0x2, 0xe, 0x9  /* subsets 0    0    0    0    */
		},
		{
			0x20a9, 0x9baa, 0x1682, 0x20a8, 0x9ba9, 0x1682,
			0x20a8, 0x9ba9, 0x1682, 0x20ab, 0x9bac, 0x1684,
			0x20a8, 0x9ba9, 0x1681, 0x20a7, 0x9ba8, 0x1681,
			0x20a8, 0x9ba9, 0x1682, 0x20ab, 0x9bac, 0x1684,
			0x20ab, 0x9bac, 0x1684, 0x20a8, 0x9ba9, 0x1681,
			0x20a8, 0x9ba9, 0x1682, 0x20a9, 0x9baa, 0x1683,
			0x20aa, 0x9bab, 0x1684, 0x20a8, 0x9ba9, 0x1681,
			0x20ab, 0x9bac, 0x1684, 0x20a9, 0x9baa, 0x1683
		},
		{
			0x1054, 0x6e2a, 0x0b41, 0x1054, 0x6e2b, 0x0b41,
			0x1054, 0x6e2b, 0x0b41, 0x1055, 0x6e29, 0x0b42,
			0x1054, 0x6e2b, 0x0b40, 0x1053, 0x6e2b, 0x0b40,
			0x1054, 0x6e2b, 0x0b41, 0x1055, 0x6e29, 0x0b42,
			0x1055, 0x6e29, 0x0b42, 0x1054, 0x6e2b, 0x0b40,
			0x1054, 0x6e2b, 0x0b41, 0x1054, 0x6e2a, 0x0b41,
			0x1055, 0x6e2a, 0x0b42, 0x1054, 0x6e2b, 0x0b40,
			0x1055, 0x6e29, 0x0b42, 0x1054, 0x6e2a, 0x0b41
		}
	},
	{
		18, /* mode */
		6, /* partition */
		{
			 { 0x0008, 0x0070, 0x00d4 },
			 { 0x0032, 0x000a, 0x0009 },
			 { 0x0014, 0x0008, 0x001a },
			 { 0x000a, 0x001c, 0x0015 }
		},
		{
			0x2, 0x0, 0x0, 0x4, /* subsets 0(a) 0    0    1    */
			0x4, 0x3, 0x3, 0x6, /* subsets 0    0    1    1    */
			0x4, 0x7, 0x5, 0x3, /* subsets 0    1    1    1    */
			0x1, 0x2, 0x5, 0x2  /* subsets 1    1    1    1(a) */
		},
		{
			0x0425, 0x6fb5, 0xa8a8, 0x083c, 0x6cfc, 0xab1c,
			0x083c, 0x6cfc, 0xab1c, 0x1602, 0x6e03, 0xb3b8,
			0x802a, 0x7295, 0xa611, 0x021a, 0x7112, 0xa76e,
			0x1785, 0x6fd4, 0xb2f7, 0x1348, 0x6abe, 0xb515,
			0x802a, 0x7295, 0xa611, 0x11ec, 0x691c, 0xb5c4,
			0x14a5, 0x6c61, 0xb467, 0x1785, 0x6fd4, 0xb2f7,
			0x1a3f, 0x7319, 0xb19a, 0x18e2, 0x7177, 0xb248,
			0x14a5, 0x6c61, 0xb467, 0x18e2, 0x7177, 0xb248
		},
		{
			0x2515, 0x37da, 0x6827, 0x041e, 0x367e, 0x66ee,
			0x041e, 0x367e, 0x66ee, 0x0b01, 0x3701, 0x629f,
			0x47e2, 0x394a, 0x6973, 0x3591, 0x3889, 0x68c4,
			0x0bc2, 0x37ea, 0x6300, 0x09a4, 0x355f, 0x61f1,
			0x47e2, 0x394a, 0x6973, 0x08f6, 0x348e, 0x619a,
			0x0a52, 0x3630, 0x6248, 0x0bc2, 0x37ea, 0x6300,
			0x0d1f, 0x398c, 0x63ae, 0x0c71, 0x38bb, 0x6357,
			0x0a52, 0x3630, 0x6248, 0x0c71, 0x38bb, 0x6357
		}
	},
	{
		22, /* mode */
		7, /* partition */
		{
			 { 0x00c4, 0x0033, 0x00af },
			 { 0x000d, 0x0023, 0x0004 },
			 { 0x001f, 0x002d, 0x000d },
			 { 0x0014, 0x0036, 0x0007 }
		},
		{
			0x2, 0x2, 0x4, 0x4, /* subsets 0(a) 0    0    0    */
			0x2, 0x4, 0x0, 0x6, /* subsets 0    0    0    1    */
			0x0, 0x3, 0x5, 0x4, /* subsets 0    0    1    1    */
			0x3, 0x2, 0x7, 0x0  /* subsets 0    1    1    1(a) */
		},
		{
			0xb711, 0x29fd, 0xcddd, 0xb711, 0x29fd, 0xcddd,
			0xb354, 0x21a6, 0xccb6, 0xb354, 0x21a6, 0xccb6,
			0xb711, 0x29fd, 0xcddd, 0xb354, 0x21a6, 0xccb6,
			0xba9c, 0x31e4, 0xcef4, 0xc4bc, 0x26fa, 0xc75a,
			0xba9c, 0x31e4, 0xcef4, 0xb54b, 0x2609, 0xcd51,
			0xc33c, 0x25c0, 0xc689, 0xc1bd, 0x2486, 0xc5b8,
			0xb54b, 0x2609, 0xcd51, 0xbe93, 0x21ef, 0xc3fe,
			0xc63c, 0x2834, 0xc82c, 0xbb94, 0x1f7c, 0xc25c
		},
		{
			0x60f3, 0x14fe, 0x558d, 0x60f3, 0x14fe, 0x558d,
			0x62d1, 0x10d3, 0x5620, 0x62d1, 0x10d3, 0x5620,
			0x60f3, 0x14fe, 0x558d, 0x62d1, 0x10d3, 0x5620,
			0x5f2e, 0x18f2, 0x5502, 0x5a1d, 0x137d, 0x58ce,
			0x5f2e, 0x18f2, 0x5502, 0x61d6, 0x1304, 0x55d3,
			0x5add, 0x12e0, 0x5937, 0x5b9d, 0x1243, 0x599f,
			0x61d6, 0x1304, 0x55d3, 0x5d32, 0x10f7, 0x5a7c,
			0x595e, 0x141a, 0x5866, 0x5eb2, 0x0fbe, 0x5b4e
		}
	},
	{
		26, /* mode */
		8, /* partition */
		{
			 { 0x00f4, 0x00ec, 0x000b },
			 { 0x0019, 0x0000, 0x003a },
			 { 0x0006, 0x0003, 0x003e },
			 { 0x0005, 0x0011, 0x002c }
		},
		{
			0x1, 0x7, 0x3, 0x7, /* subsets 0(a) 0    0    0    */
			0x1, 0x0, 0x3, 0x3, /* subsets 0    0    0    0    */
			0x4, 0x3, 0x1, 0x4, /* subsets 0    0    0    1    */
			0x7, 0x6, 0x0, 0x2  /* subsets 0    0    1    1(a) */
		},
		{
			0x8d10, 0x93dc, 0x0a52, 0x92e4, 0x93dc, 0x0554,
			0x8ef8, 0x93dc, 0x08b0, 0x92e4, 0x93dc, 0x0554,
			0x8d10, 0x93dc, 0x0a52, 0x8c1c, 0x93dc, 0x0b24,
			0x8ef8, 0x93dc, 0x08b0, 0x8ef8, 0x93dc, 0x08b0,
			0x9007, 0x93dc, 0x07c7, 0x8ef8, 0x93dc, 0x08b0,
			0x8d10, 0x93dc, 0x0a52, 0x86db, 0x9b08, 0x8170,
			0x92e4, 0x93dc, 0x0554, 0x91ef, 0x93dc, 0x0625,
			0x864c, 0x90f4, 0x0934, 0x8691, 0x95db, 0x0406
		},
		{
			0x75f3, 0x728e, 0x0529, 0x730a, 0x728e, 0x02aa,
			0x74ff, 0x728e, 0x0458, 0x730a, 0x728e, 0x02aa,
			0x75f3, 0x728e, 0x0529, 0x766e, 0x728e, 0x0592,
			0x74ff, 0x728e, 0x0458, 0x74ff, 0x728e, 0x0458,
			0x7478, 0x728e, 0x03e3, 0x74ff, 0x728e, 0x0458,
			0x75f3, 0x728e, 0x0529, 0x790e, 0x6ef7, 0x473f,
			0x730a, 0x728e, 0x02aa, 0x7384, 0x728e, 0x0312,
			0x7956, 0x7402, 0x049a, 0x7933, 0x718e, 0x2506
		}
	},
	{
		30, /* mode */
		9, /* partition */
		{
			 { 0x0010, 0x0028, 0x0036 },
			 { 0x0005, 0x0014, 0x0001 },
			 { 0x003e, 0x0034, 0x003c },
			 { 0x0004, 0x0038, 0x003a }
		},
		{
			0x1, 0x1, 0x6, 0x3, /* subsets 0(a) 0    1    1    */
			0x0, 0x2, 0x2, 0x1, /* subsets 0    1    1    1    */
			0x2, 0x6, 0x4, 0x6, /* subsets 1    1    1    1    */
			0x1, 0x5, 0x3, 0x0  /* subsets 1    1    1    1(a) */
		},
		{
			0x39f1, 0xc66a, 0xa226, 0x39f1, 0xc66a, 0xa226,
			0x0d9f, 0xa31e, 0x9819, 0x01c1, 0xa9e6, 0x94b5,
			0x3ff0, 0xdef0, 0xa8b0, 0x820f, 0xac14, 0x939e,
			0x820f, 0xac14, 0x939e, 0x85df, 0xae42, 0x9287,
			0x820f, 0xac14, 0x939e, 0x0d9f, 0xa31e, 0x9819,
			0x05fe, 0xa77a, 0x95eb, 0x0d9f, 0xa31e, 0x9819,
			0x85df, 0xae42, 0x9287, 0x09cf, 0xa54c, 0x9702,
			0x01c1, 0xa9e6, 0x94b5, 0x89b0, 0xb070, 0x9170
		},
		{
			0x1cf8, 0x4905, 0x5b27, 0x1cf8, 0x4905, 0x5b27,
			0x1885, 0x6c61, 0x71e3, 0x49af, 0x68fd, 0x7395,
			0x1ff8, 0x4e78, 0x6998, 0x597d, 0x67e6, 0x7421,
			0x597d, 0x67e6, 0x7421, 0x694a, 0x66cf, 0x74ac,
			0x597d, 0x67e6, 0x7421, 0x1885, 0x6c61, 0x71e3,
			0x3820, 0x6a33, 0x72fa, 0x1885, 0x6c61, 0x71e3,
			0x694a, 0x66cf, 0x74ac, 0x2853, 0x6b4a, 0x726f,
			0x49af, 0x68fd, 0x7395, 0x7918, 0x65b8, 0x7538
		}
	}
};

#define N_BLOCKS ARRAY_SIZE(bptc_blocks)

static void
write_bits(uint8_t *out,
	   int *offset,
	   int value,
	   int n_bits)
{
	int bit_index = *offset % 8;
	int byte_index = *offset / 8;
	int n_bits_in_byte = MIN2(n_bits, 8 - bit_index);

	*offset += n_bits;

	while (n_bits > 0) {
		out[byte_index] |= ((value & ((1 << n_bits_in_byte) - 1)) <<
				    bit_index);

		n_bits -= n_bits_in_byte;
		value >>= n_bits_in_byte;
		byte_index++;
		bit_index = 0;
		n_bits_in_byte = MIN2(n_bits, 8);
	}
}

static bool
is_anchor(const struct bptc_float_mode *mode,
	  int partition_num,
	  int texel)
{
	if (texel == 0)
		return true;

	return (mode->n_partition_bits > 0 &&
		anchor_indices[partition_num] == texel);
}

static uint16_t
extract_bitfield(const struct bptc_block *block,
		 const struct bptc_float_bitfield *bitfield)
{
	uint16_t value, tmp;
	int i;

	value = ((block->endpoints[bitfield->endpoint][bitfield->component] >>
		  bitfield->offset) &
		 ((1 << bitfield->n_bits) - 1));

	if (bitfield->reverse) {
		tmp = 0;
		for (i = 0; i < bitfield->n_bits; i++) {
			tmp <<= 1;
			if (value & 1)
				tmp |= 1;
			value >>= 1;
		}
		return tmp;
	} else {
		return value;
	}
}

static void
make_block(const struct bptc_block *block,
	   uint8_t *out)
{
	const struct bptc_float_mode *mode;
	const struct bptc_float_bitfield *bitfield;
	int offset = 0;
	int n_bits;
	uint16_t value;
	int i;

	if (block->mode >= 2) {
		mode = (bptc_float_modes +
			(((block->mode >> 1) & 0xe) | (block->mode & 1))) + 2;
	} else {
		mode = bptc_float_modes + (block->mode & 1);
	}

	memset(out, 0, BLOCK_SIZE * BLOCK_SIZE);

	if (block->mode < 2)
		write_bits(out, &offset, block->mode, 2);
	else
		write_bits(out, &offset, block->mode, 5);

	for (bitfield = mode->bitfields; bitfield->endpoint != -1; bitfield++) {
		value = extract_bitfield(block, bitfield);
		write_bits(out, &offset, value, bitfield->n_bits);
	}

	write_bits(out, &offset, block->partition, mode->n_partition_bits);

	for (i = 0; i < BLOCK_SIZE * BLOCK_SIZE; i++) {
		n_bits = mode->n_index_bits;

		if (is_anchor(mode, block->partition, i))
			n_bits--;

		write_bits(out, &offset, block->indices[i], n_bits);
	}

	assert(offset == BLOCK_BYTES * 8);
}

static GLuint
make_tex(bool is_signed)
{
	GLuint tex;
	uint8_t data[BLOCK_BYTES * N_BLOCKS];
	int i;

	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);

	for (i = 0; i < N_BLOCKS; i++)
		make_block(bptc_blocks + i, data + i * BLOCK_BYTES);

	glCompressedTexImage2D(GL_TEXTURE_2D,
			       0, /* level */
			       is_signed ?
			       GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB :
			       GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB,
			       BLOCK_SIZE * 2, BLOCK_SIZE * N_BLOCKS / 2,
			       0, /* border */
			       sizeof data,
			       data);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	return tex;
}

static bool
compare_results(const GLhalfNV *expected,
		const GLhalfNV *observed,
		int observed_rowstride)
{
	int y, x, p;

	for (y = 0; y < BLOCK_SIZE; y++) {
		for (x = 0; x < BLOCK_SIZE; x++) {
			for (p = 0; p < 3; p++) {
				if (expected[p] != observed[p]) {
					printf("Unexpected color at %i,%i:\n"
					       "  Expected: %04x %04x %04x\n"
					       "  Observed: %04x %04x %04x\n",
					       x, y,
					       expected[0],
					       expected[1],
					       expected[2],
					       observed[0],
					       observed[1],
					       observed[2]);
					return false;
				}
			}
			expected += 3;
			observed += 3;
		}

		observed += ((observed_rowstride -
			     3 * BLOCK_SIZE * sizeof (float)) /
			     sizeof (float));
	}

	return true;
}

static GLboolean
check_block(const struct bptc_block *block,
	    const GLhalfNV *get_data,
	    bool is_signed)
{
	GLboolean pass;

	printf("mode %i, partition %i\n",
	       block->mode,
	       block->partition);

	pass = compare_results(is_signed ?
			       block->signed_expected_values :
			       block->unsigned_expected_values,
			       get_data,
			       BLOCK_SIZE * 2 * 3 * sizeof (float));
	printf("glGetTexImage: %s\n", pass ? "pass" : "fail");

	return pass;
}

static void
render_texture(GLhalfNV *get_data,
	       int x, int y,
	       bool is_signed)
{
	GLuint tex;

	tex = make_tex(is_signed);

	glBindTexture(GL_TEXTURE_2D, tex);
	glEnable(GL_TEXTURE_2D);

	piglit_draw_rect_tex(x, y,
			     BLOCK_SIZE * 2, BLOCK_SIZE * N_BLOCKS / 2,
			     0.0f, 0.0f, 1.0f, 1.0f);

	glDisable(GL_TEXTURE_2D);

	glPixelStorei(GL_PACK_ALIGNMENT, 1);

	glGetTexImage(GL_TEXTURE_2D,
		      0, /* level */
		      GL_RGB,
		      GL_HALF_FLOAT,
		      get_data);

	glBindTexture(GL_TEXTURE_2D, 0);
	glDeleteTextures(1, &tex);
}

enum piglit_result
piglit_display(void)
{
	GLboolean pass = GL_TRUE;
	GLhalfNV get_data[N_BLOCKS * BLOCK_SIZE * BLOCK_SIZE * 3];
	int offset;
	int is_signed;
	int i;

	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT);

	for (is_signed = 0; is_signed < 2; is_signed++) {
		if (is_signed)
			printf("Signed texture:\n");
		else
			printf("Unsigned texture:\n");

		memset(get_data, 0, sizeof get_data);

		render_texture(get_data,
			       is_signed * BLOCK_SIZE * 2, 0, /* x/y offset */
			       is_signed);

		for (i = 0; i < N_BLOCKS; i++) {
			offset = (i % 2 * BLOCK_SIZE * 3 +
				  i / 2 * BLOCK_SIZE * BLOCK_SIZE * 2 * 3);
			pass &= check_block(bptc_blocks + i,
					    get_data + offset,
					    is_signed);
		}
	}

	piglit_present_results();

	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
}

void
piglit_init(int argc, char **argv)
{
	if (piglit_get_gl_version() < 42 &&
	    !piglit_is_extension_supported("GL_ARB_texture_compression_bptc")) {
		printf("OpenGL 4.2 or GL_ARB_texture_compression_bptc "
		       "is required.\n");
		piglit_report_result(PIGLIT_SKIP);
	}

	if (piglit_get_gl_version() < 30 &&
	    !piglit_is_extension_supported("GL_ARB_half_float_pixel")) {
		printf("OpenGL 3.0 or GL_ARB_half_float_pixel is required.\n");
		piglit_report_result(PIGLIT_SKIP);
	}

	piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
}
